package proto;

import java.awt.Color;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
* Loads a level
* @param nLevel The number of the level
* @return The level
* @author bitjaeger
*/
public abstract class Loader {
    public static Level Load(Integer nLevel) throws IOException{
        // Open the file
        BufferedReader br = new BufferedReader(new InputStreamReader(
            Proto.class.getResourceAsStream("levels\\" + nLevel + ".txt")));
        // Number of keys
        int nKeys = 0;
        // Numer of tiles in a row
        int tileCols = Integer.parseInt(br.readLine());
        // Number of tiles in a column
        int tileRows = Integer.parseInt(br.readLine());
        // Number of fields in a row
        int fieldCols = Integer.parseInt(br.readLine());
        // Number of fields in a column
        int fieldRows = Integer.parseInt(br.readLine());
        Stickman[] stickmen = new Stickman[2];
        Point[] startPositions = new Point[2];
        EmptyTile emptyTile = null;
        Door door = null;
        Tile[][] tiles = new Tile[tileCols][tileRows];
        // Start parsing tiles
        for(int row = 0; row < tileRows; ++row){
            tileLoop:
            for(int col = 0; col < tileCols; ++col){
                br.readLine(); // Empty line
                Tile tile = new Tile();
                Field[][] fields = new Field[fieldCols][fieldRows];
                for(int y = 0; y < fieldRows; ++y){
                    for(int x = 0; x < fieldCols; ++x){
                        switch(br.read()){
                            case '0': // Empty tile
                                emptyTile = new EmptyTile();
                                emptyTile.InitTile(fields);
                                tiles[col][row] = emptyTile;
                                br.readLine(); // This line is over
                                continue tileLoop;
                            case ' ': // Empty space
                                fields[x][y] = new Field();
                                break;
                            case 'X': // Brick
                                fields[x][y] = new Brick();
                                break;
                            case 'D': // Door
                                door = new Door();
                                fields[x][y] = door;
                                break;
                            case 'o': // Key
                                fields[x][y] = new Key();
                                ++nKeys;
                                break;
                            case 'A': // Stickman 0
                                fields[x][y] = new Field(Color.RED);
                                startPositions[0] = new Point(tile, x, y);
                                break;
                            case 'B': // Stickman 1
                                fields[x][y] = new Field(Color.GREEN);
                                startPositions[1] = new Point(tile, x, y);
                                break;
                        }
                        fields[x][y].Init(new Point(tile, x, y));
                    }
                    br.readLine();
                }
                // Tile parsed
                tile.InitTile(fields);
                tiles[col][row] = tile;
                // create the level
            }
        }
        stickmen[0] = new Stickman(startPositions[0],Color.RED);
        stickmen[1] = new Stickman(startPositions[1],Color.GREEN);
        // Set the neighborships
        for(int row = 0; row < tileRows; ++row){
            for(int col = 0; col < tileCols; ++col){
                //Set stickmen
                tiles[col][row].SetStickmen(stickmen);
                // Set tile neighbors
                tiles[col][row].SetNeighbor(Direction.LEFT,
                        (col == 0) ? null : tiles[col-1][row]);
                tiles[col][row].SetNeighbor(Direction.RIGHT,
                        (col == tileCols-1) ? null : tiles[col+1][row]);
                tiles[col][row].SetNeighbor(Direction.UP,
                        (row == 0) ? null : tiles[col][row-1]);
                tiles[col][row].SetNeighbor(Direction.DOWN,
                        (row == tileRows-1) ? null : tiles[col][row+1]);
                // Set field neighbors
                if(tiles[col][row] == emptyTile)
                    continue;
                for(int y = 0; y < fieldRows; ++y){
                    for(int x = 0; x < fieldCols; ++x){
                        tiles[col][row].GetField(x, y).SetNeighbor(Direction.LEFT,
                                (x == 0) ? null : tiles[col][row].GetField(x-1,y));
                        tiles[col][row].GetField(x, y).SetNeighbor(Direction.RIGHT,
                                (x == fieldCols-1) ? null : tiles[col][row].GetField(x+1,y));
                        tiles[col][row].GetField(x, y).SetNeighbor(Direction.UP,
                                (y == 0) ? null : tiles[col][row].GetField(x,y-1));
                        tiles[col][row].GetField(x, y).SetNeighbor(Direction.DOWN,
                                (y == fieldRows-1) ? null : tiles[col][row].GetField(x,y+1));
                    }
                }
            }
        }
        // set up level
        Level level = new Level(tiles, emptyTile);
        door.Init(nKeys, level);
        level.SetStartingPositions(startPositions);
        GeneralInput.Init(stickmen, level.GetEmptyTile());
        return level;
    }
}